﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace VirtualKeyboard.Controls
{
    public partial class LoopControl
    {
        #region Const
        const double BigRadius = 200.0;
        const double SmailRadius = 70.0;
        private readonly TimeSpan deltaSpan = new TimeSpan(0, 0, 0, 0, 200);
        #endregion

        #region Private
        private DateTime startTime;
        private Angle startAngle;
        #endregion

        public event RoutedEventHandler CenterClick
        {
            add { centerButton.Click += value; }
            remove { centerButton.Click -= value; }
        }

        public event EventHandler<LoopGlideEventArg> LoopGlide;

        public void OnLoopGlide(LoopGlideEventArg e)
        {
            EventHandler<LoopGlideEventArg> handler = LoopGlide;
            if (handler != null) handler(this, e);
        }

        public LoopControl()
        {
            // 为初始化变量所必需
            InitializeComponent();
        }


        protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
        {
            startTime = DateTime.Now;
            startAngle = ToAngle(e.ManipulationOrigin);
            base.OnManipulationStarted(e);
        }

        protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
        {
            if (IsInCenter(e.ManipulationOrigin)) return;

            var now = DateTime.Now;
            if (now - startTime > deltaSpan)
            {
                GetDirection(e.ManipulationOrigin);
                startTime = now;
                startAngle = ToAngle(e.ManipulationOrigin);
            }
            base.OnManipulationDelta(e);
        }

        private void GetDirection(Point point)
        {
            var angle = ToAngle(point);
            var angleDistance = startAngle - angle;
            OnLoopGlide(new LoopGlideEventArg(angleDistance.Distance));
        }

        /// <summary>
        /// 求角度
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private Angle ToAngle(Point point)
        {
            var xPoint = ToXPoint(point);
            var x = xPoint.X;
            var y = xPoint.Y;
            var angle = Math.Atan(x / y) * 180.0 / Math.PI;
            if (!(y < 0.0))
            {
                angle += 180.0;
            }
            else if (x > 0.0)
            {
                angle += 360.0;
            }
            return new Angle(angle);
        }

        /// <summary>
        /// 变化坐标
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        private Point ToXPoint(Point point)
        {
            var x = point.X - BigRadius;
            var y = point.Y - BigRadius;
            return new Point(x, y);
        }

        private bool IsInCenter(Point point)
        {
            var xPoint = ToXPoint(point);
            var radius = Math.Sqrt(xPoint.X * xPoint.X + xPoint.Y * xPoint.Y);
            return radius < SmailRadius;
        }

        #region Private Struct

        /// <summary>
        /// 角度
        /// </summary>
        private struct Angle : IEquatable<Angle>
        {
            private readonly double value;
            private const double Epsilon = 0.1;

            public double Value
            {
                get { return value; }
            }

            public Angle(double value)
            {
                if (value > 360.0 || value < 0)
                {
                    throw new ArgumentOutOfRangeException("value", "value must between 0 and 360");
                }
                this.value = value;
            }

            public override string ToString()
            {
                return string.Format("{0:N2}", value);
            }

            public static AngleDistance operator -(Angle angle1, Angle angle2)
            {
                double angleDistance = angle1.value - angle2.value;
                if (angleDistance > 180.0)
                {
                    angleDistance -= 360;
                }
                else if (angleDistance < -180.0)
                {
                    angleDistance += 360;
                }
                return new AngleDistance(angleDistance);
            }

            public override bool Equals(object obj)
            {
                if (obj is Angle)
                {
                    return Equals((Angle)obj);
                }
                return false;
            }

            public override int GetHashCode()
            {
                return 360 ^ value.GetHashCode();
            }

            public bool Equals(Angle other)
            {
                return Math.Abs(value - other.value) < Epsilon;
            }
        }

        /// <summary>
        /// 夹角
        /// </summary>
        private struct AngleDistance
        {
            private readonly double angleDistance;

            public AngleDistance(double angleDistance)
            {
                this.angleDistance = angleDistance;
            }

            public double Distance
            {
                get { return angleDistance; }
            }

            public override string ToString()
            {
                return string.Format("{0:N2}", angleDistance);
            }

            /// <summary>
            /// 顺时针
            /// </summary>
            public bool Clockwise
            {
                get { return angleDistance > 0; }
            }
        }
        #endregion


    }
}